home *** CD-ROM | disk | FTP | other *** search
/ Freelog 125 / Freelog_MarsAvril2015_No125.iso / ViePratique / ArchiFacile / ArchiFacileSetup.exe / {app} / nw.pak / Unnamed File 000123.txt < prev    next >
Text File  |  2014-10-14  |  8KB  |  250 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. cr.define('cr.ui', function() {
  6.   /**
  7.    * Constructor for FocusManager singleton. Checks focus of elements to ensure
  8.    * that elements in "background" pages (i.e., those in a dialog that is not
  9.    * the topmost overlay) do not receive focus.
  10.    * @constructor
  11.    */
  12.   function FocusManager() {
  13.   }
  14.  
  15.   FocusManager.prototype = {
  16.     /**
  17.      * Whether focus is being transferred backward or forward through the DOM.
  18.      * @type {boolean}
  19.      * @private
  20.      */
  21.     focusDirBackwards_: false,
  22.  
  23.     /**
  24.      * Determines whether the |child| is a descendant of |parent| in the page's
  25.      * DOM.
  26.      * @param {Element} parent The parent element to test.
  27.      * @param {Element} child The child element to test.
  28.      * @return {boolean} True if |child| is a descendant of |parent|.
  29.      * @private
  30.      */
  31.     isDescendantOf_: function(parent, child) {
  32.       var current = child;
  33.  
  34.       while (current) {
  35.         current = current.parentNode;
  36.         if (typeof(current) == 'undefined' ||
  37.             typeof(current) == 'null' ||
  38.             current === document.body) {
  39.           return false;
  40.         } else if (current === parent) {
  41.           return true;
  42.         }
  43.       }
  44.  
  45.       return false;
  46.     },
  47.  
  48.     /**
  49.      * Returns the parent element containing all elements which should be
  50.      * allowed to receive focus.
  51.      * @return {Element} The element containing focusable elements.
  52.      */
  53.     getFocusParent: function() {
  54.       return document.body;
  55.     },
  56.  
  57.     /**
  58.      * Returns the elements on the page capable of receiving focus.
  59.      * @return {Array.Element} The focusable elements.
  60.      */
  61.     getFocusableElements_: function() {
  62.       var focusableDiv = this.getFocusParent();
  63.  
  64.       // Create a TreeWalker object to traverse the DOM from |focusableDiv|.
  65.       var treeWalker = document.createTreeWalker(
  66.           focusableDiv,
  67.           NodeFilter.SHOW_ELEMENT,
  68.           { acceptNode: function(node) {
  69.               var style = window.getComputedStyle(node);
  70.               // Reject all hidden nodes. FILTER_REJECT also rejects these
  71.               // nodes' children, so non-hidden elements that are descendants of
  72.               // hidden <div>s will correctly be rejected.
  73.               if (node.hidden || style.display == 'none' ||
  74.                   style.visibility == 'hidden') {
  75.                 return NodeFilter.FILTER_REJECT;
  76.               }
  77.  
  78.               // Skip nodes that cannot receive focus. FILTER_SKIP does not
  79.               // cause this node's children also to be skipped.
  80.               if (node.disabled || node.tabIndex < 0)
  81.                 return NodeFilter.FILTER_SKIP;
  82.  
  83.               // Accept nodes that are non-hidden and focusable.
  84.               return NodeFilter.FILTER_ACCEPT;
  85.             }
  86.           },
  87.           false);
  88.  
  89.       var focusable = [];
  90.       while (treeWalker.nextNode())
  91.         focusable.push(treeWalker.currentNode);
  92.  
  93.       return focusable;
  94.     },
  95.  
  96.     /**
  97.      * Dispatches an 'elementFocused' event to notify an element that it has
  98.      * received focus. When focus wraps around within the a page, only the
  99.      * element that has focus after the wrapping receives an 'elementFocused'
  100.      * event. This differs from the native 'focus' event which is received by
  101.      * an element outside the page first, followed by a 'focus' on an element
  102.      * within the page after the FocusManager has intervened.
  103.      * @param {Element} element The element that has received focus.
  104.      * @private
  105.      */
  106.     dispatchFocusEvent_: function(element) {
  107.       cr.dispatchSimpleEvent(element, 'elementFocused', true, false);
  108.     },
  109.  
  110.     /**
  111.      * Attempts to focus the appropriate element in the current dialog.
  112.      * @private
  113.      */
  114.     setFocus_: function() {
  115.       var element = this.selectFocusableElement_();
  116.       if (element) {
  117.         element.focus();
  118.         this.dispatchFocusEvent_(element);
  119.       }
  120.     },
  121.  
  122.     /**
  123.      * Attempts to focus the first element in the current dialog.
  124.      */
  125.     focusFirstElement: function() {
  126.       this.focusFirstElement_();
  127.     },
  128.  
  129.     /**
  130.      * Selects first appropriate focusable element according to the
  131.      * current focus direction and element type.  If it is a radio button,
  132.      * checked one is selected from the group.
  133.      * @private
  134.      */
  135.     selectFocusableElement_: function() {
  136.       // If |this.focusDirBackwards_| is true, the user has pressed "Shift+Tab"
  137.       // and has caused the focus to be transferred backward, outside of the
  138.       // current dialog. In this case, loop around and try to focus the last
  139.       // element of the dialog; otherwise, try to focus the first element of the
  140.       // dialog.
  141.       var focusableElements = this.getFocusableElements_();
  142.       var element = this.focusDirBackwards_ ? focusableElements.pop() :
  143.                                               focusableElements.shift();
  144.       if (!element)
  145.         return null;
  146.       if (element.tagName != 'INPUT' || element.type != 'radio' ||
  147.           element.name == '') {
  148.         return element;
  149.       }
  150.       if (!element.checked) {
  151.         for (var i = 0; i < focusableElements.length; i++) {
  152.           var e = focusableElements[i];
  153.           if (e && e.tagName == 'INPUT' && e.type == 'radio' &&
  154.               e.name == element.name && e.checked) {
  155.             element = e;
  156.             break;
  157.           }
  158.         }
  159.       }
  160.       return element;
  161.     },
  162.  
  163.     /**
  164.      * Handler for focus events on the page.
  165.      * @param {Event} event The focus event.
  166.      * @private
  167.      */
  168.     onDocumentFocus_: function(event) {
  169.       // If the element being focused is a descendant of the currently visible
  170.       // page, focus is valid.
  171.       if (this.isDescendantOf_(this.getFocusParent(), event.target)) {
  172.         this.dispatchFocusEvent_(event.target);
  173.         return;
  174.       }
  175.  
  176.       // Focus event handlers for descendant elements might dispatch another
  177.       // focus event.
  178.       event.stopPropagation();
  179.  
  180.       // The target of the focus event is not in the topmost visible page and
  181.       // should not be focused.
  182.       event.target.blur();
  183.  
  184.       // Attempt to wrap around focus within the current page.
  185.       this.setFocus_();
  186.     },
  187.  
  188.     /**
  189.      * Handler for keydown events on the page.
  190.      * @param {Event} event The keydown event.
  191.      * @private
  192.      */
  193.     onDocumentKeyDown_: function(event) {
  194.       /** @const */ var tabKeyCode = 9;
  195.  
  196.       if (event.keyCode == tabKeyCode) {
  197.         // If the "Shift" key is held, focus is being transferred backward in
  198.         // the page.
  199.         this.focusDirBackwards_ = event.shiftKey ? true : false;
  200.       }
  201.     },
  202.  
  203.     /**
  204.      * Initializes the FocusManager by listening for events in the document.
  205.      */
  206.     initialize: function() {
  207.       document.addEventListener('focus', this.onDocumentFocus_.bind(this),
  208.           true);
  209.       document.addEventListener('keydown', this.onDocumentKeyDown_.bind(this),
  210.           true);
  211.     },
  212.   };
  213.  
  214.   /**
  215.    * Disable mouse-focus for button controls.
  216.    * Button form controls are mouse-focusable since Chromium 30.  We want the
  217.    * old behavior in some WebUI pages.
  218.    */
  219.   FocusManager.disableMouseFocusOnButtons = function() {
  220.     document.addEventListener('mousedown', function(event) {
  221.       if (event.defaultPrevented)
  222.         return;
  223.       var node = event.target;
  224.       var tagName = node.tagName;
  225.       if (tagName != 'BUTTON' && tagName != 'INPUT') {
  226.         do {
  227.           node = node.parentNode;
  228.           if (!node || node.nodeType != Node.ELEMENT_NODE)
  229.             return;
  230.         } while (node.tagName != 'BUTTON');
  231.       }
  232.       var type = node.type;
  233.       if (type == 'button' || type == 'reset' || type == 'submit' ||
  234.           type == 'radio' || type == 'checkbox') {
  235.         if (document.activeElement != node)
  236.           document.activeElement.blur();
  237.  
  238.         // Focus the current window so that if the active element is in another
  239.         // window, it is deactivated.
  240.         window.focus();
  241.         event.preventDefault();
  242.       }
  243.     }, false);
  244.   };
  245.  
  246.   return {
  247.     FocusManager: FocusManager,
  248.   };
  249. });
  250.